#include <iostream>
#include <vector>
#include <algorithm>
#include <string.h>
#include <set>

using namespace std;

int N, M;
unsigned long height[1000][1000];

int judge = 0;

struct Node
{
    int x; 
    int y;
    set<int> kpts;
    int been = 0;
    int signal = 0;
};

Node vis[1000][1000];

void dfs(Node &now)
{
    if(now.y == N)
    {
        now.kpts.insert(now.x);
        now.signal = 1;
    }

    int x, y;
    x = now.x + 1;
    y = now.y;
    if(x > 0 && x <= M && y > 0 && y <= N && height[x][y] < height[now.x][now.y])
    {
        if(vis[x][y].been == 1)
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        else
        {
            vis[x][y].been = 1;
            vis[x][y].x = x, vis[x][y].y = y;
            dfs(vis[x][y]);
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        }
    }

    x = now.x - 1;
    y = now.y;
    if(x > 0 && x <= M && y > 0 && y <= N && height[x][y] < height[now.x][now.y])
    {
        if(vis[x][y].been == 1)
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        else
        {
            vis[x][y].been = 1;
            vis[x][y].x = x, vis[x][y].y = y;
            dfs(vis[x][y]);
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        }
    }

    x = now.x;
    y = now.y + 1;
    if(x > 0 && x <= M && y > 0 && y <= N && height[x][y] < height[now.x][now.y])
    {
        if(vis[x][y].been == 1)
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        else
        {
            vis[x][y].been = 1;
            vis[x][y].x = x, vis[x][y].y = y;
            dfs(vis[x][y]);
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        }
    }

    x = now.x;
    y = now.y - 1;
    if(x > 0 && x <= M && y > 0 && y <= N && height[x][y] < height[now.x][now.y])
    {
        if(vis[x][y].been == 1)
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        else
        {
            vis[x][y].been = 1;
            vis[x][y].x = x, vis[x][y].y = y;
            dfs(vis[x][y]);
            now.kpts.insert(vis[x][y].kpts.begin(), vis[x][y].kpts.end());
        }
    }

}

int main()
{

    cin >> N >> M;
    for(int i = 1; i <= N; i++)
    {
        for(int j = 1; j <= M; j++)
        {
            cin >> height[j][i]; 
        }
    }

    for(int i = 1; i <= M; i++)
    {
        vis[i][1].x = i,
        vis[i][1].y = 1;
        vis[i][1].been = 1;

        dfs(vis[i][1]);
    }

    int max_id = 1;

    int ans = 0;

    vector<int> temp;

    for(int i = 1; i <= N; i++)
    {
        temp.push_back(i);
    }

    int s1, e1;
    int s2, e2;
    int now = 1;
    e1 = 0;
    e2 = 1;
    int count = 0;

    for(int i = 1; i <= M; i++)
    {
        if(vis[i][N].signal == 0)
            count ++;
    }
if(count == 0){
    for(int i = 1; i <= M; i++)
    {
        if(vis[i][1].kpts.empty())
            continue;
        int begin = *vis[i][1].kpts.begin();
        int end = *vis[i][1].kpts.rbegin();
        if(vis[i][1].kpts.size() < end - begin + 1)
            continue;
        
        if(begin <= e1 + 1)
        {
            e2 = end;
            now = i;
        }else if(begin > e1 + 1)
        {
            e1 = e2;
            ans++;
            e2 = end;
            now = i;
        }
        if(begin <= e1 + 1 && end == M)
        {
            judge = 1;
            ans ++;
            break;
        }
    }
}
if(judge)
{
    cout << judge << endl;
    cout << ans;
}else
{
    cout << judge<<endl;
    cout << count;
}
}